#pragma once

#include <iostream>
#include "level.hpp"
#include "format.hpp"
#include "sink.hpp"
#include "looper.hpp"
#include <atomic>
#include <mutex>
#include <sstream>
#include <unordered_map>

#include <stdarg.h>

namespace nhylog
{
    class Logger
    {
    public:
        // 构造日志消息对象，进行格式化，得到格式化后的日志消息字符串，然后落地输出
        using ptr = std::shared_ptr<Logger>;

        Logger(const std::string &logger_name,
               LogLevel::value limit_level,
               Formatter::ptr &formatter,
               std::vector<LogSink::ptr> &sinks)
            : _logger_name(logger_name),
              _limit_level(limit_level),
              _formatter(formatter),
              _sinks(sinks.begin(), sinks.end())
        {
        }

        void debug(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1 判断是否达到输出等级
            if (_limit_level > LogLevel::value::DEBUG)
                return;

            // 2 对fmt格式化字符串和不定参字符串组织
            va_list ap;
            va_start(ap, fmt);

            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3 4 5
            serialize(LogLevel::value::DEBUG, file, line, res);

            // 6 释放资源
            free(res);
        }

        void info(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1 判断是否达到输出等级
            if (_limit_level > LogLevel::value::INFO)
                return;

            // 2 对fmt格式化字符串和不定参字符串组织
            va_list ap;
            va_start(ap, fmt);

            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3 4 5
            serialize(LogLevel::value::INFO, file, line, res);
            // 6 释放资源
            free(res);
        }

        void warn(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1 判断是否达到输出等级
            if (_limit_level > LogLevel::value::WARN)
                return;

            // 2 对fmt格式化字符串和不定参字符串组织
            va_list ap;
            va_start(ap, fmt);

            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3 4 5
            serialize(LogLevel::value::WARN, file, line, res);
            // 6 释放资源
            free(res);
        }

        void error(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1 判断是否达到输出等级
            if (_limit_level > LogLevel::value::ERROR)
                return;

            // 2 对fmt格式化字符串和不定参字符串组织
            va_list ap;
            va_start(ap, fmt);

            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3 4 5
            serialize(LogLevel::value::ERROR, file, line, res);

            // 6 释放资源
            free(res);
        }

        void fatal(const std::string &file, size_t line, const std::string &fmt, ...)
        {
            // 1 判断是否达到输出等级
            if (_limit_level > LogLevel::value::FATAL)
                return;

            // 2 对fmt格式化字符串和不定参字符串组织
            va_list ap;
            va_start(ap, fmt);

            char *res;
            int ret = vasprintf(&res, fmt.c_str(), ap);
            if (ret == -1)
            {
                std::cout << "vasprintf error" << std::endl;
                return;
            }
            va_end(ap);

            // 3 4 5
            serialize(LogLevel::value::FATAL, file, line, res);

            // 6 释放资源
            free(res);
        }

        const std::string& Name()
        {
            //避免外界修改
            return _logger_name;
        } 
    protected:
        void serialize(LogLevel::value level, const std::string &file, size_t line, const char *res)
        {
            // 3 构造LogMsg对象
            LogMsg msg(level, line, file, _logger_name, res);

            // 4 得到日志字符串
            std::stringstream ss;
            _formatter->format(ss, msg);

            // 5 日志落地
            log(ss.str().c_str(), ss.str().size());
        }
        // 落地输出--不同日志器有不同的输出方式
        virtual void log(const char *data, size_t len) = 0;

    protected:
        // 1 落地器名字（唯一id）
        std::string _logger_name;
        // 2 限制等级
        std::atomic<LogLevel::value> _limit_level;
        // 3 格式化对象
        Formatter::ptr _formatter;
        // 4 落地方向
        std::vector<LogSink::ptr> _sinks;

        // 5 互斥锁，帮住多个线程安全日志落地
        std::mutex _mutex;
    };

    class SyncLogger : public Logger
    {
    public:
        SyncLogger(const std::string &logger_name,
                   LogLevel::value limit_level,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> &sinks)
            : Logger(logger_name, limit_level, formatter, sinks)
        {
        }

    protected:
        virtual void log(const char *data, size_t len)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            if (_sinks.empty())
                return;

            for (auto &sink : _sinks)
            {
                sink->log(data, len);
            }
        }
    };

    class AsyncLogger : public Logger 
    {
    public:
        AsyncLogger(const std::string &logger_name,
                   LogLevel::value limit_level,
                   Formatter::ptr &formatter,
                   std::vector<LogSink::ptr> &sinks,
                   AsyncType looper_type)
            : Logger(logger_name, limit_level, formatter, sinks)
            , _looper(std::make_shared<AsyncLooper>(std::bind(&AsyncLogger::realLog,this,std::placeholders::_1),looper_type))
        {
        }

        //数据写入缓冲区
        void log(const char* data,size_t len)
        {
            //push 是线程安全的
            _looper->push(data,len);
        }

        //设计一个实际落地函数，将缓冲区的数据落地
        void realLog(Buffer &buf)
        {
            if(_sinks.empty()) return;
            for(auto & sink : _sinks)
            {
                sink->log(buf.begin(),buf.readAbleSize());
            }
        }
    private:
        AsyncLooper::ptr _looper;
    };

    // 使用建造者模式。
    enum class LoggerType
    {
        LOGGER_SYNC,
        LOGGER_ASYNC
    };

    class LoggerBuider
    {
    public:
        LoggerBuider()
            : _logger_type(LoggerType::LOGGER_SYNC)
            , _limit_level(LogLevel::value::DEBUG)
            , _looper_type(AsyncType::ASYNC_SAFE)
        {

        }

        void buildLoggerType(LoggerType type)
        {
            _logger_type = type;
        }
        void buildLoggerName(const std::string &name) { _logger_name = name; }
        void buildLoggerLevel(LogLevel::value level){_limit_level = level;}
        void buildLoggerFormatter(const std::string &pattern)
        {
            _formatter = std::make_shared<Formatter>(pattern);
        }
        template <typename SinkType, typename... Args>
        void buildSink(Args &&...args)
        {
            LogSink::ptr psink = SinkFactory::create<SinkType>(std::forward<Args>(args)...);
            _sinks.push_back(psink);
        }

        //启动非安全的异步操作
        void buildEnableUnSafeAsync()
        {
            _looper_type = AsyncType::ASYNC_UNSAFE;
        }
        virtual Logger::ptr build() = 0; // 局部和全局
    protected:
        //
        LoggerType _logger_type;
        // 1 落地器名字（唯一id）
        std::string _logger_name;
        // 2 限制等级
        std::atomic<LogLevel::value> _limit_level;
        // 3 格式化对象
        Formatter::ptr _formatter;
        // 4 落地方向
        std::vector<LogSink::ptr> _sinks;
        // 5 异步工作器模式
        AsyncType _looper_type;
    };

    class LocalLoggerBuider : public LoggerBuider
    {
    public:
        Logger::ptr build() override
        {
            //必须要有日志器名称
            assert(_logger_name.empty()==false);
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }

            if(_sinks.empty())
            {
                buildSink<StdoutSink>();
            }

            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                //
                return std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }


            return std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
        }
    };

    class LoggerManager
    {
    public: 
        static LoggerManager& getInstance()
        {
            //c++11 之后针对静态局部变量，编译器在编译层面实现了线程安全。
            //此对象没有构造完成之前，其他就要阻塞等待
            static LoggerManager eton;
            return eton;
        }


        void addLogger(Logger::ptr& logger)
        {
            if(hasLogger(logger->Name())) return;

            std::unique_lock<std::mutex> lock(_mutex);
            _loggers.insert(std::make_pair(logger->Name(),logger));
        }

        bool hasLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);

            if(it == _loggers.end())
                return false;

            return true;
        }

        Logger::ptr getLogger(const std::string& name)
        {
            std::unique_lock<std::mutex> lock(_mutex);
            auto it = _loggers.find(name);
            if(it == _loggers.end())
            {
                return Logger::ptr();
            }

            return it->second;
        }

        Logger::ptr rootLogger()
        {
            return _root_logger;
        }

    private:
        LoggerManager()
        {
            //只能构造local，global会造成死循环
            std::unique_ptr<nhylog::LoggerBuider> builder(new nhylog::LocalLoggerBuider());
            builder->buildLoggerName("root");
            _root_logger = builder->build();
            _loggers.insert(std::make_pair("root",_root_logger));
        }
        

    private:
        std::mutex _mutex;
        Logger::ptr _root_logger;//默认日志器
        std::unordered_map<std::string,Logger::ptr> _loggers; 
    };

    //全局日志器的建造者，在局部基础上增加功能：将日志器添加到单例对象里
    class GlobleLoggerBuider : public LoggerBuider
    {
    public:
        Logger::ptr build() override
        {
            //必须要有日志器名称
            assert(_logger_name.empty()==false);
            if(_formatter.get() == nullptr)
            {
                _formatter = std::make_shared<Formatter>();
            }

            Logger::ptr logger;
            if(_sinks.empty())
            {
                buildSink<StdoutSink>();
            }

            if(_logger_type == LoggerType::LOGGER_ASYNC)
            {
                //
                logger = std::make_shared<AsyncLogger>(_logger_name,_limit_level,_formatter,_sinks,_looper_type);
            }
            else 
            {
                logger = std::make_shared<SyncLogger>(_logger_name,_limit_level,_formatter,_sinks);
            }

            LoggerManager::getInstance().addLogger(logger);

            return logger;
        }
    };

}